﻿using System;

namespace SoftwareConsulting.BI11.NumericalMethods.DifferentialEquations
{    
    /// <summary>
    /// Класс метода Рунге-Кутта 4го порядка для решения диф.уравнений первого порядка y'=f(x,y)
    /// в интервале [a, b] с заданным начальным условием x[0] = y0 и фиксированным шагом h = (begin - start) / pointsNumber.
    /// </summary>
    public class RungeKutta4Order
    {
        private double[,] _result;

        /// <summary>
        /// Конструктор по умолчанию
        /// </summary>
        /// <param name="function">Функция, требующая решения</param>
        /// <param name="beginPointValue">Значение начальной точки интервала</param>
        /// <param name="endPointValue">Значение конечной точки интервала</param>
        /// <param name="y0">Начальное условие</param>
        /// <param name="pointsNumber">Число точек</param>
        public RungeKutta4Order(FunctionWithTwoArguments function, double beginPointValue, double endPointValue, double y0, int pointsNumber)
        {
            _result = new double[2, pointsNumber+1];
            double k1 = 0;
            double k2 = 0;
            double k3 = 0;
            double h = (endPointValue - beginPointValue) / pointsNumber;
            double y1 = y0;
            double x = 0;
            double y = 0;
            _result[0, 0] = x;
            _result[1, 0] = y1;
            for (int i = 1; i <= pointsNumber; i++)
            {
                k1 = h * function(x, y);
                x = x + h / 2;
                y = y1 + k1 / 2;
                k2 = function(x, y) * h;
                y = y1 + k2 / 2;
                k3 = function(x, y) * h;
                x = x + h / 2;
                y = y1 + (k1 + 2 * k2 + 2 * k3 + function(x, y) * h) / 6;
                y1 = y;
                _result[0, i] = x;
                _result[1, i] = y1; 
            }            
        }
        /// <summary>
        /// Возвращает решение
        /// </summary>        
        public double[,] GetSolution()
        {
            return _result;
        }
    }
}
